package cn.edu.nju.software.zp13.core.annotationParser;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

import cn.edu.nju.software.zp13.core.annotation.Attribute;
import cn.edu.nju.software.zp13.core.annotation.Element;
import cn.edu.nju.software.zp13.core.nodeDescriptor.NodeDescriptor;
import cn.edu.nju.software.zp13.core.nodeDescriptorGenerator.NodeDescriptorGenerator;
import cn.edu.nju.software.zp13.core.nodeDescriptorGenerator.factory.NodeDescriptorGeneratorFactory;
import cn.edu.nju.software.zp13.core.xmlNodeEntity.XmlNodeEntity;

public class AnnotationParser {

	/**
	 * return tagName of a XmlNodeEntity.
	 * 
	 * @param entity
	 * 
	 * @return tagName
	 */
	public static String getTagName(XmlNodeEntity entity) {
		Class<? extends XmlNodeEntity> c = entity.getClass();
		return getTagName(c.getAnnotation(Element.class), c);
	}

	/**
	 * generate nodeDescriptor for each node in a xmlNodeEntity.
	 * 
	 * @param clazz
	 *            class of a xmlNodeEntity.
	 * @return the list of nodeDescriptors for all nodes in a xmlNodeEntity.
	 */
	public static List<NodeDescriptor> generateNodeDescriptors(XmlNodeEntity entity) {
		Class<? extends XmlNodeEntity> clazz = entity.getClass();
		List<NodeDescriptor> list = new LinkedList<>();
		Field[] fields = clazz.getDeclaredFields();
		Method[] methods = clazz.getMethods();
		for (Field f : fields) {
			f.setAccessible(true);
			NodeDescriptorGenerator ndg = NodeDescriptorGeneratorFactory.createNodeGenerator(f);
			if (ndg != null) {
				NodeDescriptor nd = ndg.generateNodeDescriptor(f, methods, entity);
				list.add(nd);
			}
		}
		return list;
	}

	/**
	 * 
	 * @param f
	 * @param a
	 * @return
	 */
	public static String getAttributeName(Field f, Attribute a) {
		return defaultValueOrDefinedValue(f.getName(), a.name());
	}

	/**
	 * 
	 * @param f
	 * @param e
	 * @return
	 */
	public static String getElementTagName(Field f, Element e) {
		return defaultValueOrDefinedValue(f.getName(), e.tagName());
	}

	private static String defaultValueOrDefinedValue(String defaultValue, String definedValue) {
		String result = definedValue;
		if ("".equals(definedValue)) {
			result = defaultValue;
		}
		return result;
	}

	/**
	 * return tagName of a XmlNodeEntity.
	 * 
	 * @param e
	 *            Annotaion Element
	 * @param c
	 *            Class<? extends XmlNodeEntity> c
	 * @return tagName
	 */
	private static String getTagName(Element e, Class<? extends XmlNodeEntity> c) {
		String tag = e.tagName();
		if ("".equals(tag)) {
			tag = c.getSimpleName();
		}
		return tag;
	}
}
